home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / cvs-1_3.lha / cvs-1.3 / src / main.c < prev    next >
C/C++ Source or Header  |  1992-03-31  |  13KB  |  445 lines

  1. /*
  2.  *    Copyright (c) 1992, Brian Berliner and Jeff Polk
  3.  *    Copyright (c) 1989-1992, Brian Berliner
  4.  *
  5.  *    You may distribute under the terms of the GNU General Public License
  6.  *    as specified in the README file that comes with the CVS 1.3 kit.
  7.  *
  8.  * This is the main C driver for the CVS system.
  9.  *
  10.  * Credit to Dick Grune, Vrije Universiteit, Amsterdam, for writing
  11.  * the shell-script CVS system that this is based on.
  12.  *
  13.  * Usage:
  14.  *    cvs [options] command [options] [files/modules...]
  15.  *
  16.  * Where "command" is composed of:
  17.  *        admin        RCS command
  18.  *        checkout    Check out a module/dir/file
  19.  *        export        Like checkout, but used for exporting sources
  20.  *        update        Brings work tree in sync with repository
  21.  *        commit        Checks files into the repository
  22.  *        diff        Runs diffs between revisions
  23.  *        log        Prints "rlog" information for files
  24.  *        add        Adds an entry to the repository
  25.  *        remove        Removes an entry from the repository
  26.  *        status        Status info on the revisions
  27.  *        rdiff        "patch" format diff listing between releases
  28.  *        tag        Add/delete a symbolic tag to the RCS file
  29.  *        rtag        Add/delete a symbolic tag to the RCS file
  30.  *        import        Import sources into CVS, using vendor branches
  31.  *        release        Indicate that Module is no longer in use.
  32.  *        history        Display history of Users and Modules.
  33.  */
  34.  
  35. #include "cvs.h"
  36. #include "patchlevel.h"
  37.  
  38. char rcsid[] = "@(#)main.c 1.64 92/03/31\n";
  39.  
  40. extern char *getenv ();
  41.  
  42. char *program_name;
  43. char *command_name = "";
  44.  
  45. int use_editor = TRUE;
  46. int cvswrite = !CVSREAD_DFLT;
  47. int really_quiet = FALSE;
  48. int quiet = FALSE;
  49. int trace = FALSE;
  50. int noexec = FALSE;
  51. int logoff = FALSE;
  52.  
  53. char *CurDir;
  54.  
  55. /*
  56.  * Defaults, for the environment variables that are not set
  57.  */
  58. char *Rcsbin = RCSBIN_DFLT;
  59. char *Editor = EDITOR_DFLT;
  60. char *CVSroot = CVSROOT_DFLT;
  61.  
  62. #if __STDC__
  63. int add (int argc, char **argv);
  64. int admin (int argc, char **argv);
  65. int checkout (int argc, char **argv);
  66. int commit (int argc, char **argv);
  67. int diff (int argc, char **argv);
  68. int history (int argc, char **argv);
  69. int import (int argc, char **argv);
  70. int cvslog (int argc, char **argv);
  71. int patch (int argc, char **argv);
  72. int release (int argc, char **argv);
  73. int cvsremove (int argc, char **argv);
  74. int rtag (int argc, char **argv);
  75. int status (int argc, char **argv);
  76. int tag (int argc, char **argv);
  77. int update (int argc, char **argv);
  78. #else
  79. int add ();
  80. int admin ();
  81. int checkout ();
  82. int commit ();
  83. int diff ();
  84. int history ();
  85. int import ();
  86. int cvslog ();
  87. int patch ();
  88. int release ();
  89. int cvsremove ();
  90. int rtag ();
  91. int status ();
  92. int tag ();
  93. int update ();
  94. #endif                /* __STDC__ */
  95.  
  96. struct cmd
  97. {
  98.     char *fullname;        /* Full name of the function (e.g. "commit") */
  99.     char *nick1;        /* alternate name (e.g. "ci") */
  100.     char *nick2;        /* another alternate names (e.g. "ci") */
  101.     int (*func) ();        /* Function takes (argc, argv) arguments. */
  102. } cmds[] =
  103.  
  104. {
  105.     { "add", "ad", "new", add },
  106.     { "admin", "adm", "rcs", admin },
  107.     { "checkout", "co", "get", checkout },
  108.     { "commit", "ci", "com", commit },
  109.     { "diff", "di", "dif", diff },
  110.     { "export", "exp", "ex", checkout },
  111.     { "history", "hi", "his", history },
  112.     { "import", "im", "imp", import },
  113.     { "log", "lo", "rlog", cvslog },
  114.     { "rdiff", "patch", "pa", patch },
  115.     { "release", "re", "rel", release },
  116.     { "remove", "rm", "delete", cvsremove },
  117.     { "status", "st", "stat", status },
  118.     { "rtag", "rt", "rfreeze", rtag },
  119.     { "tag", "ta", "freeze", tag },
  120.     { "update", "up", "upd", update },
  121.     { NULL, NULL, NULL, NULL },
  122. };
  123.  
  124. static char *usg[] =
  125. {
  126.     "Usage: %s [cvs-options] command [command-options] [files...]\n",
  127.     "    Where 'cvs-options' are:\n",
  128.     "        -H           Displays Usage information for command\n",
  129.     "        -Q           Cause CVS to be really quiet.\n",
  130.     "        -q           Cause CVS to be somewhat quiet.\n",
  131.     "        -r           Make checked-out files read-only\n",
  132.     "        -w           Make checked-out files read-write (default)\n",
  133.     "        -l           Turn History logging off\n",
  134.     "        -n           Do not execute anything that will change the disk\n",
  135.     "        -t           Show trace of program execution -- Try with -n\n",
  136.     "        -v           CVS version and copyright\n",
  137.     "        -b bindir    Find RCS programs in 'bindir'\n",
  138.     "        -e editor    Use 'editor' for editing log information\n",
  139.     "        -d CVS_root  Overrides $CVSROOT as the root of the CVS tree\n",
  140.     "\n",
  141.     "    and where 'command' is:\n",
  142.     "        add          Adds a new file/directory to the repository\n",
  143.     "        admin        Administration front end for rcs\n",
  144.     "        checkout     Checkout sources for editing\n",
  145.     "        commit       Checks files into the repository\n",
  146.     "        diff         Runs diffs between revisions\n",
  147.     "        history      Shows status of files and users\n",
  148.     "        import       Import sources into CVS, using vendor branches\n",
  149.     "        export       Export sources from CVS, similar to checkout\n",
  150.     "        log          Prints out 'rlog' information for files\n",
  151.     "        rdiff        'patch' format diffs between releases\n",
  152.     "        release      Indicate that a Module is no longer in use\n",
  153.     "        remove       Removes an entry from the repository\n",
  154.     "        status       Status info on the revisions\n",
  155.     "        tag          Add a symbolic tag to checked out version of RCS file\n",
  156.     "        rtag         Add a symbolic tag to the RCS file\n",
  157.     "        update       Brings work tree in sync with repository\n",
  158.     NULL,
  159. };
  160.  
  161. static SIGTYPE
  162. main_cleanup ()
  163. {
  164.     exit (1);
  165. }
  166.  
  167. int
  168. main (argc, argv)
  169.     int argc;
  170.     char *argv[];
  171. {
  172.     extern char *version_string;
  173.     char *cp;
  174.     struct cmd *cm;
  175.     int c, help = FALSE, err = 0;
  176.     int rcsbin_update_env, cvs_update_env;
  177.     char tmp[PATH_MAX];
  178.  
  179.     /*
  180.      * Just save the last component of the path for error messages
  181.      */
  182.     if ((program_name = rindex (argv[0], '/')) == NULL)
  183.     program_name = argv[0];
  184.     else
  185.     program_name++;
  186.  
  187.     CurDir = xmalloc (PATH_MAX);
  188.     if (!getwd (CurDir))
  189.     error (1, 0, "cannot get working directory: %s", CurDir);
  190.  
  191.     /*
  192.      * Query the environment variables up-front, so that
  193.      * they can be overridden by command line arguments
  194.      */
  195.     rcsbin_update_env = *Rcsbin;    /* RCSBIN_DFLT must be set */
  196.     if ((cp = getenv (RCSBIN_ENV)) != NULL)
  197.     {
  198.     Rcsbin = cp;
  199.     rcsbin_update_env = 0;        /* it's already there */
  200.     }
  201.     if ((cp = getenv (EDITOR_ENV)) != NULL)
  202.     Editor = cp;
  203.     if ((cp = getenv (CVSROOT_ENV)) != NULL)
  204.     {
  205.     CVSroot = cp;
  206.     cvs_update_env = 0;        /* it's already there */
  207.     }
  208.     if (getenv (CVSREAD_ENV) != NULL)
  209.     cvswrite = FALSE;
  210.  
  211.     optind = 1;
  212.     while ((c = gnu_getopt (argc, argv, "Qqrwtnlvb:e:d:H")) != -1)
  213.     {
  214.     switch (c)
  215.     {
  216.         case 'Q':
  217.         really_quiet = TRUE;
  218.         /* FALL THROUGH */
  219.         case 'q':
  220.         quiet = TRUE;
  221.         break;
  222.         case 'r':
  223.         cvswrite = FALSE;
  224.         break;
  225.         case 'w':
  226.         cvswrite = TRUE;
  227.         break;
  228.         case 't':
  229.         trace = TRUE;
  230.         break;
  231.         case 'n':
  232.         noexec = TRUE;
  233.         case 'l':            /* Fall through */
  234.         logoff = TRUE;
  235.         break;
  236.         case 'v':
  237.         (void) fputs (rcsid, stdout);
  238.         (void) fputs (version_string, stdout);
  239.         (void) sprintf (tmp, "Patch Level: %d\n", PATCHLEVEL);
  240.         (void) fputs (tmp, stdout);
  241.         (void) fputs ("\nCopyright (c) 1992, Brian Berliner and Jeff Polk\nCopyright (c) 1989-1992, Brian Berliner\n\nCVS may be copied only under the terms of the GNU General Public License,\na copy of which can be found with the CVS 1.3 distribution kit.\n", stdout);
  242.         exit (0);
  243.         break;
  244.         case 'b':
  245.         Rcsbin = optarg;
  246.         rcsbin_update_env = 1;    /* need to update environment */
  247.         break;
  248.         case 'e':
  249.         Editor = optarg;
  250.         break;
  251.         case 'd':
  252.         CVSroot = optarg;
  253.         cvs_update_env = 1;    /* need to update environment */
  254.         break;
  255.         case 'H':
  256.         help = TRUE;
  257.         break;
  258.         case '?':
  259.         default:
  260.         usage (usg);
  261.     }
  262.     }
  263.     argc -= optind;
  264.     argv += optind;
  265.     if (argc < 1)
  266.     usage (usg);
  267.  
  268.     /*
  269.      * XXX - Compatibility.  This can be removed in the release after CVS 1.3.
  270.      * Try to rename the CVSROOT.adm file to CVSROOT, unless there already is
  271.      * a CVSROOT directory.
  272.      */
  273.     if (CVSroot != NULL)
  274.     {
  275.     char rootadm[PATH_MAX];
  276.     char orootadm[PATH_MAX];
  277.  
  278.     (void) sprintf (rootadm, "%s/%s", CVSroot, CVSROOTADM);
  279.     if (!isdir (rootadm))
  280.     {
  281.         (void) sprintf (orootadm, "%s/%s", CVSroot, OCVSROOTADM);
  282.         if (isdir (orootadm))
  283.         (void) rename (orootadm, rootadm);
  284.     }
  285.     strip_path (CVSroot);
  286.     }
  287.  
  288.     /*
  289.      * Specifying just the '-H' flag to the sub-command causes a Usage
  290.      * message to be displayed.
  291.      */
  292.     command_name = cp = argv[0];
  293.     if (help == TRUE || (argc > 1 && strcmp (argv[1], "-H") == 0))
  294.     argc = -1;
  295.     else
  296.     {
  297.     /*
  298.      * Check to see if we can write into the history file.  If not,
  299.      * we assume that we can't work in the repository.
  300.      * BUT, only if the history file exists.
  301.      */
  302.     {
  303.         char path[PATH_MAX];
  304.         int save_errno;
  305.  
  306.         if (!CVSroot || !*CVSroot)
  307.         error (1, 0, "You don't have a %s environment variable",
  308.                CVSROOT_ENV);
  309.         (void) sprintf (path, "%s/%s", CVSroot, CVSROOTADM);
  310.         if (access (path, R_OK | X_OK))
  311.         {
  312.         save_errno = errno;
  313.         error (0, 0,
  314.             "Sorry, you don't have sufficient access to %s", CVSroot);
  315.         error (1, save_errno, "%s", path);
  316.         }
  317.         (void) strcat (path, "/");
  318.         (void) strcat (path, CVSROOTADM_HISTORY);
  319.         if (isfile (path) && access (path, R_OK | W_OK))
  320.         {
  321.         save_errno = errno;
  322.         error (0, 0,
  323.          "Sorry, you don't have read/write access to the history file");
  324.         error (1, save_errno, "%s", path);
  325.         }
  326.     }
  327.     }
  328.  
  329. #ifndef PUTENV_MISSING
  330.     /* Now, see if we should update the environment with the Rcsbin value */
  331.     if (cvs_update_env)
  332.     {
  333.     char *env;
  334.  
  335.     env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1);
  336.     (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot);
  337.     (void) putenv (env);
  338.     /* do not free env, as putenv has control of it */
  339.     }
  340.     if (rcsbin_update_env)
  341.     {
  342.     char *env;
  343.  
  344.     env = xmalloc (strlen (RCSBIN_ENV) + strlen (Rcsbin) + 1 + 1);
  345.     (void) sprintf (env, "%s=%s", RCSBIN_ENV, Rcsbin);
  346.     (void) putenv (env);
  347.     /* do not free env, as putenv has control of it */
  348.     }
  349. #endif
  350.  
  351.     /*
  352.      * If Rcsbin is set to something, make sure it is terminated with
  353.      * a slash character.  If not, add one.
  354.      */
  355.     if (*Rcsbin)
  356.     {
  357.     int len = strlen (Rcsbin);
  358.     char *rcsbin;
  359.  
  360.     if (Rcsbin[len - 1] != '/')
  361.     {
  362.         rcsbin = Rcsbin;
  363.         Rcsbin = xmalloc (len + 2);    /* one for '/', one for NULL */
  364.         (void) strcpy (Rcsbin, rcsbin);
  365.         (void) strcat (Rcsbin, "/");
  366.     }
  367.     }
  368.  
  369.     for (cm = cmds; cm->fullname; cm++)
  370.     {
  371.     if (cm->nick1 && !strcmp (cp, cm->nick1))
  372.         break;
  373.     if (cm->nick2 && !strcmp (cp, cm->nick2))
  374.         break;
  375.     if (!strcmp (cp, cm->fullname))
  376.         break;
  377.     }
  378.  
  379.     if (!cm->fullname)
  380.     usage (usg);            /* no match */
  381.     else
  382.     {
  383.     command_name = cm->fullname;    /* Global pointer for later use */
  384.     (void) SIG_register (SIGHUP, main_cleanup);
  385.     (void) SIG_register (SIGINT, main_cleanup);
  386.     (void) SIG_register (SIGQUIT, main_cleanup);
  387.     (void) SIG_register (SIGPIPE, main_cleanup);
  388.     (void) SIG_register (SIGTERM, main_cleanup);
  389.  
  390. #ifndef SETVBUF_MISSING
  391.     /*
  392.      * Make stdout line buffered, so 'tail -f' can monitor progress.
  393.      * Patch creates too much output to monitor and it runs slowly.
  394.      */
  395.     if (strcmp (cm->fullname, "patch"))
  396.         (void) setvbuf (stdout, (char *) NULL, _IOLBF, 0);
  397. #endif
  398.  
  399.     err = (*(cm->func)) (argc, argv);
  400.     }
  401.     /*
  402.      * If the command's error count is modulo 256, we need to change it
  403.      * so that we don't overflow the 8-bits we get to report exit status
  404.      */
  405.     if (err && (err % 256) == 0)
  406.     err = 1;
  407.     Lock_Cleanup ();
  408.     return (err);
  409. }
  410.  
  411. char *
  412. Make_Date (rawdate)
  413.     char *rawdate;
  414. {
  415.     struct tm *ftm;
  416.     time_t unixtime;
  417.     char date[256];            /* XXX bigger than we'll ever need? */
  418.     char *ret;
  419.  
  420.     unixtime = get_date (rawdate, (struct timeb *) NULL);
  421.     if (unixtime == (time_t) - 1)
  422.     error (1, 0, "Can't parse date/time: %s", rawdate);
  423. #ifdef HAVE_RCS5
  424.     ftm = gmtime (&unixtime);
  425. #else
  426.     ftm = localtime (&unixtime);
  427. #endif
  428.     (void) sprintf (date, DATEFORM,
  429.             ftm->tm_year + (ftm->tm_year < 100 ? 0 : 1900),
  430.             ftm->tm_mon + 1, ftm->tm_mday, ftm->tm_hour,
  431.             ftm->tm_min, ftm->tm_sec);
  432.     ret = xstrdup (date);
  433.     return (ret);
  434. }
  435.  
  436. void
  437. usage (cpp)
  438.     register char **cpp;
  439. {
  440.     (void) fprintf (stderr, *cpp++, program_name, command_name);
  441.     for (; *cpp; cpp++)
  442.     (void) fprintf (stderr, *cpp);
  443.     exit (1);
  444. }
  445.